import 'dart:core';

// 问题四：Error和Exception的区别

// 解释：
// Error和Exception的区别：
// 1. Error: 表示程序无法恢复的严重问题，通常不应被捕获
// 2. Exception: 表示程序可以处理的异常情况，应该被捕获
// 自定义异常场景：当业务逻辑需要特定的错误处理时

// 自定义异常类
class InsufficientBalanceException implements Exception {
  final double required; // 需要取款的金额
  final double available; // 当前可用余额

  InsufficientBalanceException(this.required, this.available);

  // 重写 toString 方法，提供更详细的错误信息
  @override
  String toString() =>
      // *** 修改点：将 $$required 和 $$available 改为 $required 和 $available ***
      'InsufficientBalanceException: 需要 $required, 但只有 $available';
}

// 模拟银行账户类
class BankAccount {
  double _balance; // 账户余额

  BankAccount(this._balance);

  // 取款方法
  void withdraw(double amount) {
    // 检查金额是否有效 (可以添加，例如 amount <= 0)
    if (amount <= 0) {
      throw ArgumentError('取款金额必须为正数'); // 抛出 Error，因为这是无效参数
    }
    // 检查余额是否充足
    if (amount > _balance) {
      // 抛出自定义的 Exception
      throw InsufficientBalanceException(amount, _balance);
    }
    // 执行取款
    _balance -= amount;
    print('成功取出 $amount');
  }

  // 获取当前余额
  double get balance => _balance;
}

void main() {
  final account = BankAccount(100.0);
  print('初始余额: ${account.balance}');

  // 场景 1: 正常取款
  print('\n--- 尝试正常取款 ---');
  try {
    account.withdraw(50.0);
    print('取款成功，当前余额: ${account.balance}');
  } catch (e) {
    // 这里理论上不应该执行，除非 withdraw 内部有其他未预料的异常
    print('取款失败: $e');
  }

  // 场景 2: 尝试超额取款，捕获自定义异常
  print('\n--- 尝试超额取款 ---');
  try {
    account.withdraw(100.0); // 余额现在是 50，取 100 会失败
    print('取款成功，当前余额: ${account.balance}'); // 这行不会执行
  } on InsufficientBalanceException catch (e) {
    // 捕获我们自定义的异常类型
    print('捕获到余额不足异常: $e');
    print('   需要: ${e.required}, 可用: ${e.available}');
  } on ArgumentError catch (e) {
    // 捕获可能的参数错误
    print('捕获到参数错误: $e');
  } on Exception catch (e) {
    // 捕获其他类型的 Exception
    print('捕获到其他 Exception: $e');
  } catch (e) {
    // 捕获所有其他未处理的 throwable (包括 Error)
    print('捕获到未预料的错误: $e');
  } finally {
    // finally 块无论是否有异常都会执行
    print('操作结束后的最终余额: ${account.balance}'); // 应该是 50.0
  }

  // 场景 3: 演示 Error (通常不建议捕获 Error，除非你知道你在做什么)
  print('\n--- 演示 Error (RangeError) ---');
  try {
    // 故意触发一个 Error
    final list = <int>[1, 2, 3];
    print('尝试访问 list[10]...');
    print(list[10]); // 这会抛出 RangeError
  } on RangeError {
    // 可以捕获特定的 Error 类型，但不推荐用于常规流程控制
    print('捕获到 RangeError: 索引超出范围！');
    // print(e); // 可以打印详细错误信息
  } catch (e) {
    // 捕获其他所有错误
    print('捕获到其他错误: $e');
  }

  print('\n程序执行完毕。');
}
